#pragma once
#include<iostream>
#include<unistd.h>
#include<vector>
#include<unordered_map>
#include<string>
#include<sstream>
#include<algorithm>
#include<sys/sendfile.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/socket.h>
#include<fcntl.h>
#include<wait.h>
#include"Util.hpp"
#include"Log.hpp"
#include <stdlib.h>
#include <sys/wait.h>

#define SEP ": "
#define WEB_ROOT "wwwroot"
#define HOME_PAGE "index.html"
#define HTTP_VERSION "HTTP/1.0"
#define LINE_END "\r\n"
#define PAGE_404 "404.html"
#define PAGE_500 " "

#define INFORMATION  100
#define OK           200
#define REDIRECTION  300  
#define BAD_REQUEST  400 
#define NOT_FOUND    404
#define SERVER_ERROR 500

// 将状态码转化为文本信息
static std::string Code2Desc(int code)
{
    std::string desc;
    switch(code)
    {
        case 200:
            desc="OK";
            break;
        case 404:
            desc="Not Found";
            break;
        default:
            break;
    }
    return desc;
}

// 将后缀名转化为对应的内容类型
static std::string Suffix2Desc(const std::string &suffix)
{
    // 用static定义变量只会初始化一次
    static std::unordered_map<std::string,std::string>suffix2desc={
        {".html","text/html"},
        {".css","text/css"},
        {".js","application/javascript"},
        {".jpg","application/x-jpg"},
        {".xml","application/xml"}
    };
    auto iter=suffix2desc.find(suffix);
    if(iter!=suffix2desc.end())
    {
        return iter->second;
    }
    return "text/html";
}
class HttpRequset
{
    public:
        std::string request_line; // 请求行
        std::vector<std::string> request_header; // 请求报头
        std::string blank; // 空行
        std::string request_boady; // 请求正文

        // 解析过后的数据
        std::string method; // 请求方法
        std::string uri; // 统一资源定位  path ? parameter
        std::string version; // 协议版本

        std::unordered_map<std::string,std::string>header_kv;

        int content_length;
        std::string path;
        std::string suffix;
        std::string query_param;

        bool cgi;
        int size;
    public:
        HttpRequset()
            :content_length(0),cgi(false)
        {}

        ~HttpRequset()
        {}

};

class HttpResponse
{
    public:
        std::string status_line; // 状态码
        std::vector<std::string> response_header; // 响应报头
        std::string blank; // 空行
        std::string response_body; // 响应正文

        int status_code;
        int fd;

    public:
        HttpResponse()
            :blank(LINE_END),status_code(OK)
        {}

        ~HttpResponse()
        {}
         
};

class EndPoint
{
    private:
        int sock;
        HttpRequset http_request;
        HttpResponse http_response;
        bool stop;
    private:
        // 读取请求行
        bool RecvHttpRequestLine()
        {
            auto &line=http_request.request_line;
            if(Util::ReadLine(sock,line)>0)
            {
                line.resize(line.size()-1);
                LOG(INFO,http_request.request_line);
            }
            else
            {
                stop=true;
            }
            return stop;
        }
        // 读取请求报头
        bool RecvHttpRequestHeader()
        {
            std::string line;
            while(true)
            {
                line.clear();
                if(Util::ReadLine(sock,line)<=0)
                {
                    stop=true;
                    break;
                }
                if(line=="\n")
                {
                    http_request.blank=line;
                    break;
                }
                line.resize(line.size()-1);
                http_request.request_header.push_back(line);
                // LOG(INFO,line);
            }
            return stop;
        }
        // 解析请求行
        void ParseHttpRequestLine()
        {
            auto &line=http_request.request_line;
            std::stringstream ss(line);
            ss>>http_request.method>>http_request.uri>>http_request.version;
            auto &method=http_request.method;
            std::transform(method.begin(),method.end(),method.begin(),::toupper);
        }
        // 解析请求报头
        void ParseHttpRequestHeader()
        {
            std::string key;
            std::string value;
            for(auto &iter:http_request.request_header)
            {
                Util::CutString(iter,key,value,SEP);
                http_request.header_kv.insert({key,value});
            }
        }
        // 是否需要读取请求正文
        bool IsNeedRecvHttpRequestBody()
        {
            auto &method=http_request.method;
            if(method=="POST")
            {
                auto &header_kv=http_request.header_kv;
                auto iter=header_kv.find("Content-Length");
                if(iter!=header_kv.end())
                {
                    http_request.content_length=atoi(iter->second.c_str());
                    return true;
                }
            }
            return false;
        }
        // 读取请求正文
        bool RecvHttpRequestBody()
        {
            if(IsNeedRecvHttpRequestBody())
            {
                int content_length=http_request.content_length;
                auto &body=http_request.request_boady;
                char ch=0;
                while(content_length)
                {
                    ssize_t s=recv(sock,&ch,1,0);
                    if(s>0)
                    {
                        body.push_back(ch);
                        content_length--;
                    }
                    else
                    {
                        stop=true;
                        break;
                    }
                }
                LOG(INFO,body);
            }
            return stop;
        }

        // 处理CGI机制
        int ProcessCgi()
        {
            int exit_code=OK;
            // LOG(INFO,"process cgi method");
            auto &method=http_request.method;
            auto &query_param=http_request.query_param; // GET
            auto &body_text=http_request.request_boady; // POST
            auto &bin=http_request.path;
            int content_length=http_request.content_length;
            auto &response_body=http_response.response_body;

            std::string query_param_env;
            std::string method_env;
            std::string content_length_env;

            // 创建匿名管道来通信
            int input[2];
            int output[2];

            if(pipe(input)<0)
            {
                LOG(ERROR,"pipe input create error");
                exit_code=SERVER_ERROR;
                return exit_code;
            }
            if(pipe(output)<0)
            {
                LOG(ERROR,"pipe output create error");
                exit_code=SERVER_ERROR;
                return exit_code;
            }
            
            // 创建子进程，用子程序去执行CGI程序
            // 相对于用户来说，只有一个httpserver进程在执行
            pid_t pid=fork();
            if(pid==0) // 子进程
            {
                close(input[0]);
                close(output[1]);
                
                // 将method环境变量添加到当前进程的环境变量中
                method_env="METHOD=";
                method_env+=method;
                std::cout<<"cgi: "<<method_env<<std::endl;
                putenv(const_cast<char*>(method_env.c_str()));

                if(method=="GET") // get方法通过用环境变量(putenv)将参数添加到当前进程的环境变量
                {
                    query_param_env="QUERY_PARAM=";
                    query_param_env+=query_param;
                    putenv(const_cast<char*>(query_param_env.c_str()));
                }
                else if(method=="POST")
                {
                    //将content_length环境变量添加到当前进程的环境变量中
                    content_length_env="CONTENT_LENGTH=";
                    content_length_env+=std::to_string(content_length);
                    putenv(const_cast<char*>(content_length_env.c_str()));
                    LOG(INFO,"post method, add content length");
                }
                else
                {
                    ;
                }

                // 子进程角度 input[1]:写出 output[0]:读入
                // 重定向对应的读写文件描述符
                dup2(output[0],0);
                dup2(input[1],1);

                // excel 参数1:执行程序路径 2:执行程序的方式 3:执行结果
                // 程序替换:替换代码和数据并不替换内核进程相关的数据结构(包括:文件描述表)
                execl(bin.c_str(),bin.c_str(),nullptr);
                exit(1);
            }
            else if(pid<0) // 创建进程失败
            {
                LOG(ERROF,"fork error");
                exit_code=SERVER_ERROR;
                return exit_code;
            }
            else // pid>0 父进程
            {
                close(input[1]);
                close(output[0]);

                if(method=="POST") // POST从请求正文中读取数据
                {
                    const char* start=body_text.c_str();
                    int completed=0;
                    int writed_size=0;
                    while((completed<content_length)&&(writed_size=write(output[1],start+completed,body_text.size()-completed))>0)
                    {                       
                        completed+=writed_size;
                    }
                }
                // 父进程获取子进程执行cgi程序后的结果
                char ch=0;
                while(read(input[0],&ch,1)>0)
                {
                    response_body.push_back(ch);
                }
                
                int status=0;
                pid_t ret=waitpid(pid,&status,0);
                if(ret==pid)
                {
                    if(WIFEXITED(status)) // 进程正常退出
                    {
                        if(WEXITSTATUS(status)==0) // 进程正常退出并且退出码为0
                        {
                            exit_code=OK;
                        }
                        else
                        {
                            exit_code=BAD_REQUEST;
                        }
                    }
                    else
                    { 
                        exit_code=SERVER_ERROR;
                    }
                }

                close(input[0]);
                close(output[1]);
            }
            return exit_code;
        }

        // 处理错误代码为404的状况
        void HandlerError(std::string page)
        {
            http_request.cgi=false;
            // 给用户返回对应的404页面
            http_response.fd=open(page.c_str(),O_RDONLY);
            if(http_response.fd>0)
            {
                struct stat st;
                stat(page.c_str(),&st); // 处理404
                http_request.size=st.st_size;
                
                std::string line="Content-Type: text/html";
                line+=LINE_END;
                http_response.response_header.push_back(line);

                line="Content-Length: ";
                line+=std::to_string(st.st_size);
                line+=LINE_END;
                http_response.response_header.push_back(line);
                
            }
        }

        // 处理非CGI，返回一个静态网页
        int  ProcessNonCgi()
        {
            // 响应行
            http_response.fd=open(http_request.path.c_str(),O_RDONLY);
            if(http_response.fd>=0)
            {
                return OK;
            }
            return NOT_FOUND;
        }

        void BuildHttpResponseOk()
        {
            std::string line="Content-Type: ";
            line+=Suffix2Desc(http_request.suffix);
            line+=LINE_END;
            http_response.response_header.push_back(line);

            line="Content-Length: ";
            if(http_request.cgi) // POST
            {
                line+=std::to_string(http_response.response_body.size());
            }
            else // GET
            {
                line+=std::to_string(http_request.size);
            }
            line+=LINE_END;
            http_response.response_header.push_back(line);
        }

        void BuildHttpResponseError()
        {
            // 构建响应行 [http/1.0 200 OK]
            auto &code=http_response.status_code;
            auto &status_line=http_response.status_line;
            status_line+=HTTP_VERSION;
            status_line+=" ";
            status_line+=std::to_string(code);
            status_line+=" ";
            status_line+=Code2Desc(code);
            status_line+=LINE_END;

            // 根据不同的状态码构建响应正文
            std::string path=WEB_ROOT;
            path+="/";
            switch(code)
            {
                case OK:
                    BuildHttpResponseOk();
                    break;
                case NOT_FOUND:
                    path+=PAGE_404;
                    HandlerError(path);
                    break;
                case BAD_REQUEST:
                    path+=PAGE_404;
                    HandlerError(path);
                    break;
                case SERVER_ERROR:
                    path+=PAGE_404;
                    HandlerError(path);
                    break;
                default:
                    break;
            }
        }
    public:
        EndPoint(int _sock)
        :sock(_sock),stop(false)
        {}
        bool IsStop()
        {
            return stop;
        }
        void RecvHttpRequest() // 读取请求
        {
            // 只有当读取请求行和请求报头都没有问题时才需要继续解析
            if((!RecvHttpRequestLine())&&(!RecvHttpRequestHeader()))
            {
                ParseHttpRequestLine(); // 解析请求行
                ParseHttpRequestHeader(); // 解析请求报头
                RecvHttpRequestBody(); // 读取正文
            }

        }
        void BuildHttpResponse() // 建立响应
        {
            std::string _path;
            int size=0;
            std::size_t found=0;
            // 目前只处理GET和POST方法
            auto &code=http_response.status_code;
            if(http_request.method!="GET"&&http_request.method!="POST")
            {
                LOG(WARNING,"method is not right");
                code=BAD_REQUEST;
                goto END;
            }
            // 处理GET方法
            if(http_request.method=="GET")
            {
                ssize_t pos=http_request.uri.find('?');
                if(pos!=std::string::npos)
                {
                    Util::CutString(http_request.uri,http_request.path,http_request.query_param,"?");
                    http_request.cgi=true;
                }
                else
                {
                    http_request.path=http_request.uri;
                }
            }
            // 处理POST方法
            else if(http_request.method=="POST")
            {
                http_request.path=http_request.uri;
                http_request.cgi=true;
            }
            else
            {
                ;
            }

            //处理资源路径
            _path=http_request.path;
            http_request.path=WEB_ROOT;
            http_request.path+=_path;
            if(http_request.path[http_request.path.size()-1]=='/')
            {
                http_request.path+=HOME_PAGE;
            }

            // 判断资源路径是否存在
            struct stat st;
            if(stat(http_request.path.c_str(),&st)==0)
            {
                // 说明获取资源路径成功
                if(S_ISDIR(st.st_mode))
                {
                    // 说明请求的资源是一个目录，不被允许
                    http_request.path+="/";
                    http_request.path+=HOME_PAGE;
                    stat(http_request.path.c_str(),&st);
                }
                if((st.st_mode&S_IXUSR)||(st.st_mode&S_IXGRP)||(st.st_mode&S_IXOTH))
                {
                    // 说明请求的资源是一个可执行程序
                    http_request.cgi=true;
                }
                size=st.st_size;
                http_request.size=size;    
            }
            else
            {
                // 资源路径不存在
                std::string info=http_request.path;
                info+=" Not Found!";
                LOG(WARNING,info);
                code=NOT_FOUND;
                goto END;
            }
            // 提取文件的后缀名
            found=http_request.path.rfind(".");
            if(found==std::string::npos)
            {
                // 默认设置为html格式
                http_request.suffix=".html";
            }
            else
            {
                http_request.suffix=http_request.path.substr(found);
            }
            // 是否为CGI机制
            if(http_request.cgi)
            {
                // 执行目标程序，拿到执行结果：http_response.response_body;
                code=ProcessCgi();
            }
            else
            {
                // 1. 目标网页一定是存在的
                // 2. 返回并不是单单返回网页，而是要构建HTTP响应
                code=ProcessNonCgi();
            }
END:
        BuildHttpResponseError(); //状态行填充了，响应报头也有了，空行也有了，正文有了
        }
        void sendHttpResponse() // 返回响应
        {
            // 发送响应状态行
            send(sock,http_response.status_line.c_str(),http_response.status_line.size(),0);
            // 发送响应报头
            for(auto &iter:http_response.response_header)
            {
                send(sock,iter.c_str(),iter.size(),0);
            }
            // 发送响应空行
            send(sock,http_response.blank.c_str(),http_response.blank.size(),0);
            // 发送响应正文
            if(http_request.cgi)
            {
                auto &response_body=http_response.response_body;
                size_t writed_num=0;
                size_t completed=0;
                const char* start=response_body.c_str();
                while((completed<response_body.size())&&(writed_num=send(sock,start+completed,response_body.size()-completed,0))>0)
                {
                    completed+=writed_num;
                }
            }
            else
            {
                sendfile(sock,http_response.fd,nullptr,http_request.size);
                close(http_response.fd);
            }
        }
        ~EndPoint()
        {}

};

// class Entrance
// {
//     public:
//     static void* HandlerRequest(void* _sock)
//     {
//         LOG(INFO,"handler request begin");
//         int sock=*(int*)_sock;
//         delete(int*)_sock;
//         // std::cout <<"get a new link ... : "<< sock << std::endl;
        
// #ifdef DEBUG
//         char buffer[4096];
//         recv(sock,buffer,sizeof(buffer),0);
//         std::cout <<"----------------------------begin----------------------------"<< std::endl;
//         std::cout<<buffer<<std::endl;
//         std::cout <<"-----------------------------end-----------------------------"<< std::endl;
// #else
//         EndPoint* ep=new EndPoint(sock);
//         ep->RecvHttpRequest();
//         if(!ep->IsStop())
//         {
//             LOG(INFO,"recv no error,begin build response and send data");
//             ep->BuildHttpResponse();
//             ep->sendHttpResponse();
//         }
//         else
//         {
//             LOG(WARNING,"recv error,stop build response and send data");
//         }
//         delete ep;
// #endif

//         // std::string line;
//         // Util::ReadLine(sock,line);
//         // std::cout<<line<<std::endl;
//         // close(sock);
//         LOG(INFO,"handler request end");
//         return nullptr;
//     }   
// };

class CallBack
{
    public:
    CallBack()
    {}
    void operator()(int sock)
    {
        HandlerRequest(sock);
    }
    void HandlerRequest(int _sock)
    {
        
    }
    
    ~CallBack()
    {}
};